package org.eoti.ai.bayesian.example1;

import org.eoti.ai.bayesian.BayesianNetwork;
import org.eoti.io.file.FileMonitor;
import org.eoti.io.file.FileUtil;
import org.eoti.io.file.event.FileChangedEvent;
import org.eoti.io.file.event.FileChangedListener;
import org.eoti.util.RuntimeUtil;
import org.eoti.util.ShutdownHookListener;

import java.io.*;

public class ExampleNetwork
extends BayesianNetwork<String>
implements FileChangedListener, ShutdownHookListener
{
    private File badTrainDir, goodTrainDir, testSrcDir, testBadDir, testGoodDir;
    private boolean done = false;
    
    public static void main(String ... args)
    {
        ExampleNetwork network = new ExampleNetwork();
    }

    public ExampleNetwork()
    {
        addRule(new WordRule(), 0.75);
        addRule(new SentenceRule(), 0.80);
        addRule(new ParagraphRule(), 0.95);

        File currentDir = new File(".");
        File home = new File(currentDir, "bayesian");
        File train = new File(home, "train");
        File test = new File(home, "test");

        badTrainDir = new File(train, "bad");
        badTrainDir.mkdirs();
        goodTrainDir = new File(train, "good");
        goodTrainDir.mkdirs();
        testSrcDir = new File(test, "source");
        testSrcDir.mkdirs();
        testBadDir = new File(test, "bad");
        testBadDir.mkdirs();
        testGoodDir = new File(test, "good");
        testGoodDir.mkdirs();

        FileMonitor.addFileChangedListener(this, badTrainDir, 1000);
        FileMonitor.addFileChangedListener(this, goodTrainDir, 1000);
        FileMonitor.addFileChangedListener(this, testSrcDir, 1000);

        System.out.format("To train data, drop a text file into:\n");
        System.out.format("\t%s\n", badTrainDir.getAbsolutePath());
        System.out.format("\t%s\n", goodTrainDir.getAbsolutePath());
        System.out.format("To test data, drop a text file into:\n");
        System.out.format("\t%s\n", testSrcDir.getAbsolutePath());
        System.out.format("Results will then be categorized into:\n");
        System.out.format("\t%s\n", testBadDir.getAbsolutePath());
        System.out.format("\t%s\n", testGoodDir.getAbsolutePath());

        RuntimeUtil.addShutdownHook(this);
        while(!done)
        {
            try{Thread.sleep(1000);}catch(Exception e){}
        }
    }

    @Override
    public void fileChanged(FileChangedEvent event)
    {
        try{
            File dir = event.getFile();
            String path = dir.getAbsolutePath();
            if(path.equals(badTrainDir.getAbsolutePath()))
            {
                for(File file : badTrainDir.listFiles())
                    train(file, false);
            }else if(path.equals(goodTrainDir.getAbsolutePath())){
                for(File file : goodTrainDir.listFiles())
                    train(file, true);
            }else if(path.equals(testSrcDir.getAbsolutePath())){
                for(File file : testSrcDir.listFiles())
                    handle(file);
            }
        }catch(Exception e){
            System.err.format("Exception: %s\n", e.getMessage());
        }
    }

    private String load(File file) throws IOException {
        StringBuilder sb = new StringBuilder();
        BufferedReader in = new BufferedReader(new FileReader(file));
        String line = "";
        while(  (line = in.readLine()) != null )
            sb.append(String.format("%s\n", line));

        in.close();
        return sb.toString();
    }

    private void handle(File file) throws IOException {
        double good = isGood(load(file));
        double bad = 1.0-good; // isBad(load(file));
        if(good > bad)
        {
            file.renameTo(new File(testGoodDir, file.getName()));
            System.out.format("%s marked as good\n", file.getName());
        }else{
            file.renameTo(new File(testBadDir, file.getName()));
            System.out.format("%s marked as bad\n", file.getName());
        }
    }

    private void train(File file, boolean isGoodData) throws IOException {
        System.out.format("Training %s\n", file.getName());
        train(load(file), isGoodData);
        System.out.format("%s trained.\n", file.getName());
        file.delete();
    }

    @Override
    public void shutdown() {
        FileMonitor.removeFileChangedListener(this, badTrainDir);
        FileMonitor.removeFileChangedListener(this, goodTrainDir);
        FileMonitor.removeFileChangedListener(this, testSrcDir);

        done = true;
    }
}
